#pragma once

#include <fstream>
#include <boost/algorithm/string.hpp>
#include "cppjieba/Jieba.hpp"
#include <mutex>

#include "log.hpp"

namespace util_ns{
    struct FileUtil{
        static bool readFile(const std::string &path, std::string *out){
            std::ifstream input(path, std::ios::in);
            if(!input.is_open()){
                std::cerr << "open file " << path << " error" << std::endl;
                return false;
            }
            std::string line;
            while(std::getline(input, line)){
                *out += line;
            }
            input.close();
            return true;
        }
        static bool existsFile(const std::string &path){
            std::ifstream in(path);
            return in.good();
        }
    };
    struct StringUtil{
        static void CutString(const std::string &target,const std::string &sep, std::vector<std::string> *result){
            boost::split(*result ,target, boost::is_any_of(sep), boost::token_compress_on);// 连续的sep压缩成一个
        }
    };

    class JiebaUtil{
    private:
        cppjieba::Jieba jieba;
        std::unordered_map<std::string, bool> stop_words;
    private:
        JiebaUtil():jieba("dict/jieba.dict.utf8",
                    "dict/hmm_model.utf8",
                    "dict/user.dict.utf8",
                    "dict/idf.utf8",
                    "dict/stop_words.utf8")
        {}
        JiebaUtil(const JiebaUtil&) = delete;
    public:
        // 2025年11月19日12:13:43 这块多线程可能不安全，恰好GetInstance() 内部调用了。
        void InitStopWords(){
            std::ifstream in("dict/stop_words.utf8", std::ios::in);
            if(!in.is_open()){
                ERROR_LOG("InitStopWords Error!\n");
                return;
            }
            std::string line;
            while(std::getline(in, line)) stop_words[line] = true;
            in.close();
            NORM_LOG("InitStopWords: loaded %zu stop words\n", stop_words.size());
        }
        // 2025年11月19日12:21:53 主要是这个函数不支持可重入
        static JiebaUtil *GetInstance(){
            // c++ 保证了静态对象初始化线程安全
            static JiebaUtil *instance = new JiebaUtil();
            return instance;
        }
        //去掉暂停词
        void CutString_aux(const std::string &src, std::vector<std::string> *out){
            jieba.CutForSearch(src, *out);
            for(auto iter = out->begin(); iter != out->end();){
                auto word_pos = stop_words.find(*iter);
                if(word_pos != stop_words.end()){
                    iter = out->erase(iter);
                }else{
                    ++iter;
                }
            }
        }

        static void WordSplit(const std::string &src, std::vector<std::string> *out){
            //
            const auto &inst = GetInstance();
            static std::once_flag flag;
            std::call_once(flag,[&]{
                inst->InitStopWords();
            });
            inst->CutString_aux(src, out);
        }
    };
}